package com.zyd.blog.common;

import com.alibaba.fastjson.JSON;
import com.zyd.blog.util.IpUtil;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.NamedThreadLocal;
import org.springframework.stereotype.Component;
import org.springframework.validation.support.BindingAwareModelMap;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Aspect
@Component
public class RequestResponseLogAop {

    private static final Logger logger = LogManager.getLogger(RequestResponseLogAop.class);

    private NamedThreadLocal<Long> threadLocal = new NamedThreadLocal("StopWatch");

    @Pointcut("execution(* com.zyd.blog.controller.*.*(..))")
    public void pointcut() {
    }

    @Before("pointcut()")
    public void logRequestParams(JoinPoint joinPoint) {
        // 开始时间
        threadLocal.set(System.currentTimeMillis());

        Object[] args = joinPoint.getArgs();
        //过滤序列化异常
        Stream<?> stream = ArrayUtils.isEmpty(args) ? Stream.empty() : Arrays.stream(args);
        List<Object> logArgs = stream.filter(arg -> (
                !(arg instanceof HttpServletRequest)
                        && !(arg instanceof HttpServletResponse)
                        && !(arg instanceof MultipartFile)
                        && !(arg instanceof BindingAwareModelMap))
        ).collect(Collectors.toList());

        String fullClassName = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String remoteHost = IpUtil.getRealIp(request);
        logger.info("Request Client Host:{}", remoteHost);
        logger.info("Request URI:{}, API:{}", request.getRequestURI(), fullClassName + "." + methodName);
        logger.info("Request Body:{}", JSON.toJSONString(logArgs));
    }

    @AfterReturning(returning = "response", pointcut = "pointcut()")
    public void logResponseBody(Object response) {
        if (response != null) {
            //响应信息
            logger.info("Response Body:{}", JSON.toJSONString(response));
        }
        //计算请求处理耗时,单位:秒
        Long timeConsume = (System.currentTimeMillis() - threadLocal.get());
        if (timeConsume > (2 * 1000)) {
            logger.warn("请求处理耗时:{}", timeConsume + " ms");
        } else {
            logger.info("请求处理耗时:{}", timeConsume + " ms");
        }
        threadLocal.remove();
    }
}
